<template>
  <div class="container" ref="containerVc"></div>
  <div ref="statsVc"></div>
</template>

<script setup lang="ts">

import {onMounted, ref} from "vue";
import {
  ACESFilmicToneMapping,
  AmbientLight, AnimationMixer,
  AxesHelper, Clock,
  Color, DirectionalLight, EquirectangularReflectionMapping, Fog, GridHelper, MathUtils,
  PerspectiveCamera,
  Scene,
  WebGLRenderer
} from "three";
//@ts-ignore
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
//@ts-ignore
import {FBXLoader} from "three/examples/jsm/loaders/FBXLoader";
import Stats from "stats.js";
//@ts-ignore
import {Object3D} from "three/src/core/Object3D";
import {RGBELoader} from "three/examples/jsm/loaders/RGBELoader";
import {DRACOLoader} from "three/examples/jsm/loaders/DRACOLoader";
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader";

let containerVc = ref<HTMLDivElement>();
let statsVc = ref<HTMLDivElement>();

let stats: Stats;
let camera: PerspectiveCamera;
let scene: Scene;
let grid: GridHelper;
let renderer: WebGLRenderer;
let controls: OrbitControls;


//拿到汽车轮子
const wheels = [];

/**
 * 初始化相机
 */
function initCamera() {
  camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
  camera.position.set(4.25, 1.4, -4.5);
  // camera.lookAt(scene.position)
}

/**
 * 初始化场景
 */
function initScene() {
  scene = new Scene();
  // scene.background = new Color(0x000000);
  scene.fog = new Fog(0x333333, 10, 15);

  //设置场景贴图
  new RGBELoader()
      .setPath('envTexture/')
      .load('industrial_sunset_puresky_2k.hdr', (texture: any) => {
        texture.mapping = EquirectangularReflectionMapping;
        scene.background = texture;
        scene.environment = texture;
      })


  //添加网格
  grid = new GridHelper(100, 30, 0xffffff, 0x808080);
  grid.material.opacity = 0.2;
  grid.material.depthWrite = false;
  grid.material.transparent = true;
  scene.add(grid);

  //添加一个坐标系
  let axes = new AxesHelper(30)
  scene.add(axes)

}

/**
 * 渲染器
 */
function initRenderer() {
  renderer = new WebGLRenderer({antialias: true});
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setClearColor(new Color(0xeeeeee));
  renderer.toneMapping = ACESFilmicToneMapping;
  renderer.toneMappingExposure = 0.85;
  containerVc.value.appendChild(renderer.domElement)//将渲染出来的东西挂载到Dom结点上
}

/**
 * 窗口尺寸改变的回调
 */
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderScene();
}

/**
 * 鼠标控制
 */
function initControls() {
  controls = new OrbitControls(camera, renderer.domElement);
  controls.maxDistance = 9;
  // controls.addEventListener('change', () => renderer);
  controls.maxPolarAngle = MathUtils.degToRad(90);//设置最大极角
  controls.target.set(0, 0.5, 0);
  controls.update();
  window.addEventListener('resize', onWindowResize)
}

//递归渲染
function renderScene() {

  controls.update();
  let time = -performance.now() / 1000;
  wheels.forEach((item) => {
    item.rotation.x = time * Math.PI * 2;
  });
  requestAnimationFrame(renderScene);
  renderer.render(scene, camera);
  stats.update()//性能统计更新
}

/**
 * 加载模型
 */
function loaderModel() {
  const dracoLoader = new DRACOLoader();
  dracoLoader.setDecoderPath('./draco/');

  const loader = new GLTFLoader();
  loader.setDRACOLoader(dracoLoader);

  loader.load('models/ferrari.glb', (gltfObj) => {
    const carModel = gltfObj.scene.children[0];
    wheels.push(
        carModel.getObjectByName('wheel_fl'),
        carModel.getObjectByName('wheel_fr'),
        carModel.getObjectByName('wheel_rl'),
        carModel.getObjectByName('wheel_rr'),
    );

    scene.add(carModel);
  })


}

/**
 * 初始化灯光
 */
function initLight() {
  //平行光
  let Dirlight = new DirectionalLight(0xffffff, 2.0);
  Dirlight.position.set(0, 10, 0);
  Dirlight.castShadow = true
  scene.add(Dirlight)
  //环境光
  let ambientLight = new AmbientLight(0xffffff, 0.5);
  scene.add(ambientLight)
}


function initStatas() {
  stats = new Stats();
  statsVc.value.appendChild(stats.dom);
}

//初始化函数
function init() {
  initScene();//场景
  initLight();//灯光
  initCamera();//相机
  loaderModel();//模型
  initStatas();//性能监视
  initRenderer();//渲染
  initControls();//轨道控制
}

onMounted(() => {
  if (containerVc.value && statsVc.value) {
    init();
    renderScene();
  }
})


</script>

<style scoped lang="scss">
.container {
  height: 100vh;
  width: 100vw;
}
</style>